package com.ideaaedi.springcloud.jd.user.config.properties;

import com.google.common.collect.Sets;
import com.ideaaedi.springcloud.jd.commonds.constant.BaseConstant;
import com.ideaaedi.springcloud.jd.commonds.constant.TimeConstant;
import com.ideaaedi.springcloud.jd.commonds.enums.oauth2.ScopeEnum;
import com.ideaaedi.springcloud.jd.user.config.client.ExtBaseClientDetails;
import com.ideaaedi.springcloud.jd.user.service.SysApiResourceService;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * client ak sk 配置
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img
 * src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 2021.0.1.A
 */
@Data
@RefreshScope
@Configuration
@ConfigurationProperties(prefix = "oauth2.config")
public class ClientDetailProperties {
    
    @NestedConfigurationProperty
    private List<SimpleClientDetails> clients;
    
    /**
     * 简单的客户端信息 BaseClientDetails
     */
    @Data
    public static class SimpleClientDetails {
        
        /**
         * 客户端id
         */
        private String clientId;
        
        /**
         * 客户端秘钥
         */
        private String clientSecret;
        
        /**
         * 指定角色id
         */
        private List<Long> roleIds;
        
        /**
         * 虚拟用户id （客户端模式登录，不是用户登录，是没有用户id的，但是我们程序在记录一些信息时，是需要用到用户id的，所以可以提供一个虚拟的用户id）
         */
        private Long virtualUserId;
    
        /**
         * 租户
         */
        private String tenant;
    
        /**
         * 可读数据范围的deptId对应的deptPath
         */
        private String readDataScopePathsJsonArr;
    
        /**
         * 可写(修改/删除)数据范围的deptId对应的deptPath
         */
        private String updateDataScopePathsJsonArr;
        
        /**
         * accessToken失效时间
         */
        private Integer accessTokenValiditySeconds = TimeConstant.DAY_1;
    
        /**
         * refreshToken失效时间
         */
        private Integer refreshTokenValiditySeconds = TimeConstant.DAY_7;
        
        /**
         * 校验数据是否合法
         *
         * @return true-合法；false-非法
         */
        public boolean valid () {
            if (StringUtils.isAnyBlank(clientId, clientSecret, tenant)) {
                return false;
            }
            if (virtualUserId == null) {
                return false;
            }
            return !CollectionUtils.isEmpty(roleIds);
        }
        
        /**
         * 转换为oauth2的BaseClientDetails对象
         */
        public ExtBaseClientDetails convertToBaseClientDetails(SysApiResourceService sysApiResourceService, PasswordEncoder passwordEncoder) {
            ExtBaseClientDetails clientDetails = new ExtBaseClientDetails();
            clientDetails.setClientId(this.clientId);
            clientDetails.setClientSecret(passwordEncoder.encode(this.clientSecret));
            List<SimpleGrantedAuthority> authorities = this.roleIds.stream()
                    .filter(Objects::nonNull)
                    .map(String::valueOf)
                    .map(SimpleGrantedAuthority::new)
                    .collect(Collectors.toList());
            clientDetails.setTenant(this.tenant);
            clientDetails.setReadDataScopePathsJsonArr(this.readDataScopePathsJsonArr);
            clientDetails.setUpdateDataScopePathsJsonArr(this.updateDataScopePathsJsonArr);
            clientDetails.setVirtualUserId(this.virtualUserId);
            clientDetails.setAuthorities(authorities);
            clientDetails.setScope(Sets.newHashSet(ScopeEnum.SYSTEM_ALL.getScope()));
            clientDetails.setResourceIds(Sets.newHashSet(BaseConstant.SYSTEM_INNER_RESOURCE_ID));
            clientDetails.setAuthorizedGrantTypes(Sets.newHashSet("client_credentials", "refresh_token"));
            clientDetails.setRegisteredRedirectUri(Collections.emptySet());
            clientDetails.setAutoApproveScopes(Sets.newHashSet(BaseConstant.FALSE));
            clientDetails.setAccessTokenValiditySeconds(this.accessTokenValiditySeconds);
            clientDetails.setRefreshTokenValiditySeconds(this.refreshTokenValiditySeconds);
            return clientDetails;
        }
    }
}
